//
//  ViewController.m
//  justTest
//
//  Created by 小零钱 on 2018/2/28.
//  Copyright © 2018年 小零钱. All rights reserved.
//

#import "ViewController.h"
#import "NSObject+Property.h"
#import "Father.h"
#import <objc/message.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
//    // 用例1
//    UIImage * image = [UIImage imageNamed:@"123"];
//
//    // 用例2
//    NSObject * obj = [NSObject new];
//    obj.name = @"小马";
//    obj.height = 1.83;
//    NSLog(@"runtime动态添加属性：name = %@, height = %.2f", obj.name, obj.height);
//
//    // 用例3
//    Father * f = [[Father alloc] init];
//    //默认father没有实现run：方法，可以通过performSelector调用，但是会报错。动态方法就不会报错
//    [f performSelector:@selector(run:) withObject:@10];
//
//    // 用例4
//    [self answer];
    
    [self runtimeWithClass];
}


#pragma mark - 动态变量控制
- (void)answer {
    Father * xiaoming = [[Father alloc] init];
    
    unsigned int count = 0;
    //动态获取 XiaoMing 类中的所有属性 [当然包括私有]
    Ivar * ivarList = class_copyIvarList(xiaoming.class, &count);
    for (int i = 0; i < count; i++) {
        Ivar var = ivarList[i];
        //遍历属性找到对应name字段
        const char * varName = ivar_getName(var);
        NSString * name = [NSString stringWithUTF8String:varName];
        if ([name isEqualToString:@"_age"]) {
            //修改对应的字段值成22
            object_setIvar(xiaoming, var, @"22");
            break;
        }
    }
    NSLog(@"xiaoming's age is %@", xiaoming.age);
}



#pragma mark - runtime下Class的各项操作
- (void)runtimeWithClass {
    /**** TODO: 部分一 ************************************/
    unsigned int count;
    
    //1、获取属性列表
    objc_property_t *propertyList = class_copyPropertyList([self class], &count);
    for (unsigned int i = 0; i < count; i++) {
        objc_property_t property = propertyList[i];
        const char *propertyName = property_getName(property);
        NSLog(@"获取属性列表 property---->%@", [NSString stringWithUTF8String:propertyName]);
    }
    
    //2、获取方法列表
    Method *methodList = class_copyMethodList([self class], &count);
    for (unsigned int i = 0; i < count; i++) {
        Method method = methodList[i];
        SEL methodName = method_getName(method);
        NSLog(@"获取方法列表 method---->%@", NSStringFromSelector(methodName));
    }
    
    //3、获取成员变量列表
    Ivar *ivarList = class_copyIvarList([self class], &count);
    for (unsigned int i = 0; i < count; i++) {
        Ivar myIvar = ivarList[i];
        const char *ivarName = ivar_getName(myIvar);
        NSLog(@"获取成员变量列表 Ivar---->%@", [NSString stringWithUTF8String:ivarName]);
    }
    
    //4、获取协议列表
    __unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
    for (unsigned int i = 0; i < count; i++) {
        Protocol *myProtocal = protocolList[i];
        const char *protocolName = protocol_getName(myProtocal);
        NSLog(@"获取协议列表 protocol---->%@", [NSString stringWithUTF8String:protocolName]);
    }
    
    
    /**** TODO: 部分二 ************************************/
    /*
     现在有一个Father类，和father创建的xiaoming对象,有test1和test2两个方法
    */
    Father * xiaoming = [[Father alloc] init];
    
    //1、获得类方法
    Class fatherClass = object_getClass([Father class]);
    SEL oriSEL = @selector(test1);
    Method oriMethod = class_getClassMethod(fatherClass, oriSEL);
    NSLog(@"获得类方法 oriMethod--->%@", oriMethod);
    
    //2、获得实例方法
    Class fatherClass1 = object_getClass([xiaoming class]);
    SEL oriSEL1 =@selector(test2);
    Method cusMethod = class_getInstanceMethod(fatherClass1, oriSEL1);
    NSLog(@"获得实例方法 cusMethod--->%@", cusMethod);
    
    //3、添加方法
    BOOL addSucc = class_addMethod(fatherClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(oriMethod));
    
    //4、替换原方法实现
    class_replaceMethod(fatherClass, oriSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
    
    //5、交换两个方法的实现
    method_exchangeImplementations(oriMethod, cusMethod);
    
    
    /**** TODO: 部分三 ************************************/
//    //1、得到类的所有方法
//    Method * allMethods = class_copyMethodList([Father class], &count);
//
//    //2、得到所有成员变量
//    Ivar * allVariables = class_copyIvarList([Father class], &count);
//
//    //3、得到所有属性
//    objc_property_t * properties = class_copyPropertyList([Father class], &count);
//
//    //4、根据名字得到类变量的Ivar指针，但是这个在OC中好像毫无意义
//    Ivar oneIvar = class_getClassVariable([Father class], "age");
//
//    //5、根据名字得到实例变量的Ivar指针
//    Ivar oneIvar1 = class_getInstanceVariable([Father class], "age");
//    //找到后可以直接对私有变量赋值
//    object_setIvar(xiaoming, oneIvar1, @"25"); ////强制修改age属性
//
//    /*6、 动态添加方法：
//        第一个参数表示Class cls 类型；
//        第二个参数表示待调用的方法名称；
//        第三个参数(IMP)myAddingFunction，IMP是一个函数指针，这里表示指定具体实现方法myAddingFunction；
//        第四个参数表方法的参数，0代表没有参数；
//    */
//    class_addMethod([xiaoming class], @selector(sayHi), (IMP)myAddingFunction, 0);
//
//    //7、交换两个方法
//    method_exchangeImplementations(method1, method2);
//
//    /*8、关联两个对象：
//     id object                     :表示关联者，是一个对象，变量名理所当然也是object
//     const void *key               :获取被关联者的索引key
//     id value                      :被关联者，这里是一个block
//     objc_AssociationPolicy policy :关联时采用的协议，有assign，retain，copy等协议，一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
//     */
//    objc_setAssociatedObject(id  _Nonnull object, const void * _Nonnull key, id  _Nullable value, objc_AssociationPolicy policy);
//
//    // 获得某个类的类方法
//    Method class_getClassMethod(Class  _Nullable __unsafe_unretained cls, SEL  _Nonnull name);
//    // 交换两个方法的实现
//    void method_exchangeImplementations(Method m1 , Method m2)
//    // 将某个值跟某个对象关联起来，将某个值存储到某个对象中
//    void objc_setAssociatedObject(id object , const void *key ,id value ,objc_AssociationPolicy policy)
//    // 利用参数key 将对象object中存储的对应值取出来
//    id objc_getAssociatedObject(id object , const void *key)
//    // 获得某个类的所有成员变量（outCount 会返回成员变量的总数）
//    Ivar *class_copyIvarList(Class cls , unsigned int *outCount)
//    // 获得成员变量的名字
//    const char *ivar_getName(Ivar v)
//    // 获得成员变量的类型
//    const char *ivar_getTypeEndcoding(Ivar v)
//    // 获取类里面所有方法
//    class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)//本质:创建谁的对象
//    // 获取类里面属性
//    class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
}



- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
